package com.kth.subtranslator.ui.controller;

import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
import javax.swing.SwingWorker;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.kth.subtranslator.IBatchTranslateCallBack;
import com.kth.subtranslator.ITranslateDriver;
import com.kth.subtranslator.SrtEntry;
import com.kth.subtranslator.SrtParser;
import com.kth.subtranslator.TranslateEngine.Language;
import com.kth.subtranslator.evt.EndTranslateEvent;
import com.kth.subtranslator.evt.FileSelectedEvent;
import com.kth.subtranslator.evt.StartTranslateEvent;
import com.kth.subtranslator.evt.StopTranslateEvent;
import com.kth.subtranslator.ui.DriverConfigurationDialog;
import com.kth.subtranslator.ui.SaveSubDialog;
import com.kth.subtranslator.ui.TranslateDialog;
import com.kth.subtranslator.ui.SaveSubDialog.ISaveListener;
import com.kth.subtranslator.ui.TranslateDialog.Action;

public class MenuItemsController {

	private final SrtPanelController srtController;
	private final JFrame frame;
	private JMenuBar view;
	private JMenuItem menuItem;
	private JMenuItem translateMenuItem;
	private JMenuItem menuItemSave;
	private final SaveSubDialog saveDialog;
	private final TranslateDialog translateDialog;
	private EventBus eventBus;
	private final MenuBarController menuBarController;
	private JMenuItem optionMenu;
	private final DriverConfigurationDialog configurationDialog;

	public MenuItemsController(SrtPanelController srtController, MenuBarController menuBarController, JFrame frame, EventBus eventBus) {
		this.srtController = srtController;
		this.menuBarController = menuBarController;
		this.frame = frame;
		this.eventBus = eventBus;

		eventBus.register(this);

		//
		saveDialog = new SaveSubDialog();
		saveDialog.setLocationRelativeTo(frame);
		saveDialog.setVisible(false);

		//
		translateDialog = new TranslateDialog();
		translateDialog.setLocationRelativeTo(frame);
		translateDialog.setVisible(false);

		//
		configurationDialog = new DriverConfigurationDialog(srtController);
		configurationDialog.setLocationRelativeTo(frame);
		configurationDialog.setVisible(false);
	}

	public void createView() {
		JMenuBar menuBar = new JMenuBar();
		//Build the first menu.
		JMenu menu = new JMenu("File");
		menu.setMnemonic(KeyEvent.VK_F);
		menu.getAccessibleContext().setAccessibleDescription(
				"The only menu in this program that has menu items");
		menuBar.add(menu);

		menuItem = new JMenuItem("Load Subtitle", KeyEvent.VK_L);
		menuItem.setAccelerator(KeyStroke.getKeyStroke(
				KeyEvent.VK_L, ActionEvent.ALT_MASK));
		menuItem.getAccessibleContext().setAccessibleDescription(
				"Load subtitle from your filesystem");

		menuItem.addActionListener( new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				final JFileChooser fc = new JFileChooser();
				fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
				int returnVal = fc.showOpenDialog(frame);
				if (returnVal == JFileChooser.APPROVE_OPTION) {
					final File file = fc.getSelectedFile();
					new SwingWorker<List<SrtEntry>, Void>() {

						@Override
						protected List<SrtEntry> doInBackground() throws Exception {
							SrtParser parser = new SrtParser();
							List<SrtEntry> entries = parser.parse(file.getAbsolutePath());
							return entries;
						}

						@Override
						protected void done() {
							try {
								List<SrtEntry> entries = get();
								srtController.setSourceEntries(entries);
								srtController.setSourceFile(file);
								srtController.clearTargetEntries();
								getTranslateMenuItem().setEnabled(true);
								frame.setTitle( "Subtitle Translator ("+ srtController.getSourceFile().getName() + ")");
								eventBus.post( new FileSelectedEvent() {

									@Override
									public File getFile() {
										return file;
									}

									@Override
									public Language getLanguage() {
										return Language.ENGLISH;
									}
								});
							} catch (InterruptedException e) {
								throw new RuntimeException(e);
							} catch (ExecutionException e) {
								throw new RuntimeException(e.getCause());
							}
						}

					}.execute();
				}

			}
		});

		menu.add(menuItem);

		translateMenuItem = new JMenuItem("Translate", KeyEvent.VK_T);
		translateMenuItem.setAccelerator(KeyStroke.getKeyStroke(
				KeyEvent.VK_T, ActionEvent.ALT_MASK));
		translateMenuItem.getAccessibleContext().setAccessibleDescription(
				"Start translation");
		translateMenuItem.setEnabled(false);
		translateMenuItem.addActionListener( new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {

				translateDialog.getLanguageCombo().removeAllItems();
				for (Language lang : menuBarController.getSelectedDriver().getSupportedTargetLanguage(srtController.getSourceLanguage() )) {
					if (!lang.equals( menuBarController.getSelectedLanguage() )) {
						translateDialog.getLanguageCombo().addItem( lang );	
					}
				}

				translateDialog.setVisible(true);


				if (translateDialog.getInputValue().equals(Action.OK) ) {
					final Language toLang = (Language)translateDialog.getLanguageCombo().getSelectedItem();
					final ITranslateDriver driver = menuBarController.getSelectedDriver();
					srtController.clearTargetEntries();
					eventBus.post(new StartTranslateEvent() {});
					new SwingWorker<List<SrtEntry>, SrtEntry> () {

						@Override
						protected List<SrtEntry> doInBackground() throws Exception {
							IBatchTranslateCallBack cb = new IBatchTranslateCallBack() {

								@Override
								public void onBatchTranslated(Collection<String> texts, int batchStartPos) {
									int i = 0;
									for (Iterator<String> iterator = texts.iterator(); iterator.hasNext();) {
										String translatedText = iterator.next();
										SrtEntry s = srtController.getSourceEntries().get(batchStartPos + i);
										SrtEntry targetEntry = new SrtEntry(batchStartPos + i, s.getStartTime(), s.getEndTime(), translatedText);
										publish(targetEntry);
									}
								}
							};
							return srtController.translate(driver, srtController.getSourceEntries(), toLang, cb);
						}

						@Override
						protected void process(List<SrtEntry> chunks) {
							srtController.addTargetEntries(chunks);
						}

						protected void done() {
							try {
								List<SrtEntry> translatedSrt = get();
								srtController.setTargetEntries(translatedSrt);
								setSaveMenuItemEnable(true);
							} catch (InterruptedException e) {
								throw new RuntimeException(e);
							} catch (ExecutionException e) {
								throw new RuntimeException(e);
							}
							finally {
								eventBus.post(new EndTranslateEvent() {} );
							}
						};

					}.execute();				    
				}
			}
		});


		menu.add(translateMenuItem);

		menuItemSave = new JMenuItem("Save", KeyEvent.VK_S);
		menuItemSave.setAccelerator(KeyStroke.getKeyStroke(
				KeyEvent.VK_S, ActionEvent.CTRL_MASK));
		menuItemSave.getAccessibleContext().setAccessibleDescription(
				"Save translation");
		menuItemSave.setEnabled(false);

		menuItemSave.addActionListener( new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				showSaveDialog();
			}
		});

		menu.add(menuItemSave);
		menu.addSeparator();

		optionMenu = new JMenuItem("Options");
		optionMenu.setEnabled(false);
		optionMenu.addActionListener( new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				configurationDialog.setVisible(true);
			}
		});
		menu.add(optionMenu);

		JMenuItem exitItem = new JMenuItem( new AbstractAction("Exit") {

			@Override
			public void actionPerformed(ActionEvent e) {
				getEventBus().post( new StopTranslateEvent() {} );
				getFrame().dispose();
			}
		});
		
		menu.addSeparator();
		menu.add(exitItem);

		JMenu helpMenu = new JMenu("Help");
		JMenuItem item = new JMenuItem( new AbstractAction("Website") {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					Desktop.getDesktop().browse( new URI("https://code.google.com/p/subtitle-translator/") );
				} catch (IOException e1) {
					e1.printStackTrace();
				} catch (URISyntaxException e1) {
					e1.printStackTrace();
				}
			}
		});
		helpMenu.add(item);
		JMenuItem bugReportItem = new JMenuItem( new AbstractAction("Report an Issue") {

			@Override
			public void actionPerformed(ActionEvent e) {
				try {
					Desktop.getDesktop().browse( new URI("http://code.google.com/p/subtitle-translator/issues/entry") );
				} catch (IOException e1) {
					e1.printStackTrace();
				} catch (URISyntaxException e1) {
					e1.printStackTrace();
				}
			}
		});
		helpMenu.add(bugReportItem);
		
		menuBar.add(helpMenu);

		frame.setJMenuBar(menuBar);
	}

	private void setSaveMenuItemEnable(boolean enable) {
		menuItemSave.setEnabled(enable);
	}

	public void showSaveDialog() {
		saveDialog.setVisible(true);
	}

	public void addSaveListener(ISaveListener l) {
		this.saveDialog.addSaveListener(l);
	}

	public JMenuItem getTranslateMenuItem() {
		return translateMenuItem;
	}

	@Subscribe
	public void startTranslate(StartTranslateEvent evt) {
		setSaveMenuItemEnable(false);
	}

	@Subscribe
	public void stopTranslate(EndTranslateEvent evt) {
		setSaveMenuItemEnable(true);
	}
	
	/**
	 * @return the frame
	 */
	private JFrame getFrame() {
		return frame;
	}
	
	/**
	 * @return the eventBus
	 */
	private EventBus getEventBus() {
		return eventBus;
	}

}
